from datetime import datetime
from datetime import timedelta
from elixir import *

from bumblebee.lib.database import callbacks

#
# some constants and mappings to descriptive names
#

CHANCE_LOW          = 1
CHANCE_MEDIUM       = 2
CHANCE_HIGH         = 3
chance_codes        = { CHANCE_LOW:     'Low', 
                        CHANCE_MEDIUM:  'Medium', 
                        CHANCE_HIGH:    'High' }

chance_list = [ (CHANCE_LOW, 'Low'),
                (CHANCE_LOW, 'Medium'),
                (CHANCE_LOW, 'High'), ]

IMPACT_LOW          = 1
IMPACT_MEDIUM       = 2
IMPACT_HIGH         = 3
impact_codes        = { IMPACT_LOW:     'Low', 
                        IMPACT_MEDIUM:  'Medium', 
                        IMPACT_HIGH:    'High' }

impact_list = [ (IMPACT_LOW,    'Low'),
                (IMPACT_MEDIUM, 'Medium'),
                (IMPACT_HIGH,   'High'), ]

STATUS_NOT_STARTED      = 1
STATUS_ON_SCHEDULE      = 2
STATUS_BEHIND_SCHEDULE  = 3
STATUS_COMPLETE         = 4
status_codes            = { STATUS_NOT_STARTED:     'Not Started', 
                            STATUS_ON_SCHEDULE:     'On Schedule', 
                            STATUS_BEHIND_SCHEDULE: 'Behind Schedule', 
                            STATUS_COMPLETE:        'Complete' }

class Project(Entity):
    has_field('name', Unicode(255), required=True)
    has_field('description', Unicode)
    has_field('archived', Boolean, default=False)
    has_field('created', DateTime, default=datetime.utcnow)
    has_field('status', Integer, default=STATUS_NOT_STARTED)
    belongs_to('parent_project', of_kind='Project')
    belongs_to('contact', of_kind='bumblebee.model.User')
    has_many('issues', of_kind='Issue', order_by=['-impact', '-created']) 
    has_many('risks', of_kind='Risk', order_by=['-impact', '-created']) 
    has_many('questions', of_kind='Question') 
    has_many('answers', of_kind='Answer') 
    has_many('notes', of_kind='Note', order_by=['-created']) 
    has_many('subprojects', of_kind='Project') 
    has_many('files', of_kind='ProjectFile', order_by=['-created']) 
    using_options(tablename='projects', order_by=['-created'])

    @property
    def status_code(self):
        return status_codes[self.status]

    @property
    def recent_notes(self):
        now = datetime.now()
        delta = timedelta(15)
        return [note for note in self.notes 
                if (now - note.created <= delta) or
                   (note.last_edited is not None and
                    now - note.last_edited <= delta)]
    
    @property
    def open_risks(self):
        return [risk for risk in self.risks if not risk.closed]
        
    @property
    def closed_risks(self):
        return [risk for risk in self.risks if risk.closed]

    @property
    def open_issues(self):
        return [issue for issue in self.issues if not issue.closed]

    @property
    def closed_issues(self):
        return [issue for issue in self.issues if issue.closed]

    @property
    def delayed(self):
        if self.status == STATUS_BEHIND_SCHEDULE:
            return True
        for s in self.subprojects:
            if s.delayed:
                return True
        return False
   
    @property
    def delayed_subprojects(self):
        return [subproject for subproject in self.subprojects if subproject.delayed]

    @property
    def total_questions(self):
        questions = [q for q in self.questions]
        for s in self.subprojects:
            questions.extend(s.questions)       
        return questions
  
    @property
    def total_answers(self):
        answers = [q for q in self.answers]
        for s in self.subprojects:
            answers.extend(s.answers)       
        return answers

    @property    
    def total_files(self):
        list1 = [file for file in self.files]
        list2 = [file for subproject in self.subprojects for file in subproject.files]
        
        return list1 + list2

    @property        
    def total_risks(self):
        list1 = [risk for risk in self.risks if not risk.closed]
        list2 = [risk for subproject in self.subprojects for risk in subproject.risks if not risk.closed] 
        
        return list1 + list2

    @property
    def total_issues(self):
        list1 = [issue for issue in self.issues if not issue.closed]
        list2 = [issue for subproject in self.subprojects for issue in subproject.issues if not issue.closed]
        
        return list1 + list2

    @property
    def total_notes(self):
        list1 = [note for note in self.notes]
        list2 = [note for subproject in self.subprojects for note in subproject.notes]
        
        return list1 + list2

    @property
    def new_notes(self):
        now = datetime.now()
        delta = timedelta(hours=24)
        list1 = [note for note in self.notes 
                if (now - note.created <= delta) or
                   (note.last_edited is not None and
                    now - note.last_edited <= delta)]
                                      
        list2 = [note for subproject in self.subprojects for note in subproject.notes 
                 if (now - note.created <= delta) or
                   (note.last_edited is not None and
                    now - note.last_edited <= delta)]
        
        return list1 + list2

    @property
    def new_risks(self):
        now = datetime.now()
        delta = timedelta(hours=24)
        list1 = [risk for risk in self.risks if (now - risk.created <= delta and not risk.closed)]
        list2 = [risk for subproject in self.subprojects for risk in subproject.risks 
                     if (now - risk.created <= delta and not risk.closed)]
        
        return list1 + list2

    @property
    def new_issues(self):
        now = datetime.now()
        delta = timedelta(hours=24)
        list1  = [issue for issue in self.issues if (now - issue.created <= delta and not issue.closed)]
        list2 =  [issue for subproject in self.subprojects for issue in subproject.issues 
                   if (now - issue.created <= delta and not issue.closed)]

        return list1 + list2

    @property
    def new_files(self):
        now = datetime.now()
        delta = timedelta(hours=24)
        list1 = [file for file in self.files if (now - file.created <= delta)]
        list2 = [file for subproject in self.subprojects for file in subproject.files 
                     if (now - file.created <= delta)]    
                     
        return list1 + list2

    @property
    def new_questions(self):
        now = datetime.now()
        delta = timedelta(hours=24)
        new_questions = []

        def is_new(question):
            if(now - question.created <= delta):
                return True
            for answer in question.answers:
                if (now - answer.created <= delta):
                    return True
            return False

        new_questions = [q for q in self.questions if is_new(q)]
        for s in self.subprojects:
            new_questions.extend(s.new_questions)

        return new_questions

class Issue(Entity):
    has_field('issue', Unicode)
    has_field('impact', Integer)
    has_field('closed', Boolean, default=False)
    has_field('created', DateTime, default=datetime.utcnow)
    belongs_to('project', of_kind='Project')
    belongs_to('creator', of_kind='bumblebee.model.User')
    using_options(tablename='issues', order_by=['-impact', '-created'])

    def _get_impact_code(self):
        return impact_codes[self.impact]

    impact_code = property(_get_impact_code)

class Risk(Entity):
    has_field('description', Unicode)
    has_field('chance', Integer)
    has_field('impact', Integer)
    has_field('closed', Boolean, default=False)
    has_field('created', DateTime, default=datetime.utcnow)
    belongs_to('project', of_kind='Project')
    belongs_to('creator', of_kind='bumblebee.model.User')
    using_options(tablename='risks', order_by=['-impact', '-created'])

    @property
    def impact_code(self):
        return impact_codes[self.impact]

    @property
    def chance_code(self):
        return chance_codes[self.chance]

class Note(Entity):
    has_field('note', Unicode)
    has_field('created', DateTime, default=datetime.utcnow)
    has_field('last_edited', DateTime)
    belongs_to('project', of_kind='Project')
    belongs_to('creator', of_kind='bumblebee.model.User')
    using_options(tablename='notes', order_by=['-created'])
    callbacks.before_update('_set_last_edited')

    def _set_last_edited(self):
        self.last_edited = datetime.utcnow()

class Question(Entity):
    has_field('question', Unicode)
    has_field('created', DateTime, default=datetime.utcnow)
    belongs_to('project', of_kind='Project')
    belongs_to('creator', of_kind='bumblebee.model.User')
    has_many('answers', of_kind='Answer')
    using_options(tablename='questions', order_by=['-created'])

class Answer(Entity):
    has_field('answer', Unicode)
    has_field('created', DateTime, default=datetime.utcnow)
    belongs_to('project', of_kind='Project')
    belongs_to('question', of_kind='Question')
    belongs_to('creator', of_kind='bumblebee.model.User')
    using_options(tablename='answers', order_by=['-created'])

class ProjectFile(Entity):
    has_field('filename', Unicode)
    has_field('systemfilename', Unicode)
    has_field('created', DateTime, default=datetime.utcnow)
    belongs_to('project', of_kind='Project')
    belongs_to('creator', of_kind='bumblebee.model.User')
    using_options(tablename='files', order_by=['-created'])

